package com.xmhmyh.generalframework.project.systool.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xmhmyh.generalframework.common.BaseServiceImpl;
import com.xmhmyh.generalframework.common.SpringContextHolder;
import com.xmhmyh.generalframework.common.enums.QuartzJobEnum;
import com.xmhmyh.generalframework.common.enums.ResponseCode;
import com.xmhmyh.generalframework.common.utils.MyBeanUtils;
import com.xmhmyh.generalframework.common.utils.QuartzUtils;
import com.xmhmyh.generalframework.framework.exceptions.ManageExceptions;
import com.xmhmyh.generalframework.project.sys.entity.User;
import com.xmhmyh.generalframework.project.systool.dto.QuartzJobDTO;
import com.xmhmyh.generalframework.project.systool.entity.QuartzJob;
import com.xmhmyh.generalframework.project.systool.mapper.QuartzJobMapper;
import com.xmhmyh.generalframework.project.systool.service.IQuartzJobService;
import org.quartz.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * 定时任务业务层
 *
 * @author zzx
 */
@DependsOn("springContextHolder")
@Service
public class QuartzJobServiceImpl extends BaseServiceImpl<QuartzJobMapper, QuartzJob> implements IQuartzJobService {
    private static final String GROUP_NAME = "DEFAULT";
    private static final String METHOD_NAME = "execute";

    @Qualifier("schedulerFactoryBean")
    @Autowired
    private Scheduler scheduler;


    @Override
    public void saveHandler(User user, QuartzJobDTO quartzJobDTO) {
        if (!cronIsValid(quartzJobDTO.getCronExpression())) {
            throw new ManageExceptions(ResponseCode.CRON_ERROR);
        }
        if (null == quartzJobDTO.getId()) {
            // 新增
            addJob(user, quartzJobDTO);
        } else {
            // 编辑
            updateJob(user, quartzJobDTO);
        }
    }

    @Override
    public Object getAllRunningJob() throws SchedulerException {
        Set<JobKey> jobs = QuartzUtils.getJobs(scheduler);
        return jobs;
    }

    public static boolean cronIsValid(String cronExpression) {
        return CronExpression.isValidExpression(cronExpression);
    }

    /**
     * 被 @PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。
     * 创建数据库中的所有定时任务
     *
     * @throws SchedulerException
     */
    @Override
    @PostConstruct
    public void init() throws SchedulerException {
        //先清理定时任务
        QuartzUtils.clear(scheduler);
        //获得数据库中定时任务列表
        List<QuartzJob> quartzJobList = findAll();
        for (QuartzJob quartzJob : quartzJobList) {
            // 判断任务状态是否为可用
            if (quartzJob.getStatus() == QuartzJobEnum.RESUME.getValue()) {
                //创建定时任务
                QuartzUtils.createJob(quartzJob, scheduler);
            }
        }
    }

    /**
     * 获得数据库中的任务列表
     *
     * @return 任务列表
     */
    public List<QuartzJob> findAll() {
        LambdaQueryWrapper<QuartzJob> lambdaQueryWrapper = new LambdaQueryWrapper<QuartzJob>();
        lambdaQueryWrapper.eq(QuartzJob::getStatus, QuartzJobEnum.RESUME.getValue());
        List<QuartzJob> list = list(lambdaQueryWrapper);
        return list;
    }

    /**
     * 添加定时任务
     *
     * @throws SchedulerException
     * @params User 用户 QuartzJobDTO 任务实体类
     */
    @Transactional(rollbackFor = Exception.class)
    public void addJob(User user, QuartzJobDTO quartzJobDTO) {

        QuartzJob quartzJob = new QuartzJob();
        BeanUtils.copyProperties(quartzJobDTO, quartzJob);
        quartzJob.setGroupName(GROUP_NAME);
        quartzJob.setStatus(QuartzJobEnum.PAUSE.getValue());
        quartzJob.setId(uidGenerator.getUID());
        MyBeanUtils.setSysInfo(quartzJob, user.getId(), user.getAccountId());
        //开启定时任务
        QuartzUtils.createJob(quartzJob, scheduler);
        // 加入数据库
        save(quartzJob);
    }


    @Override
    public void run(Long id) {
        QuartzJob quartzJob = selectById(id);
        Object bean = null;
        try {
            bean = SpringContextHolder.getBean(quartzJob.getBeanName());
        } catch (Exception e) {
            throw new ManageExceptions(ResponseCode.NOT_FOUND_BEAN);
        }
        Method method = null;
        try {
            method = bean.getClass().getDeclaredMethod(METHOD_NAME, JobExecutionContext.class);
            if (null != method) {
                method.invoke(bean, new Object[]{null});
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 修改定时任务
     *
     * @params User 用户信息 quartzJob 任务实体类
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateJob(User user, QuartzJobDTO quartzJobDTO) {
        QuartzJob old = getById(quartzJobDTO.getId());
        if (old == null) {
            throw new ManageExceptions(ResponseCode.ENTITY_NOT_FIND);
        }
        QuartzJob quartzJob = new QuartzJob();
        BeanUtils.copyProperties(quartzJobDTO, quartzJob);
        quartzJob.setCreateTime(old.getCreateTime());
        quartzJob.setCreateBy(old.getCreateBy());
        MyBeanUtils.updateSysInfo(quartzJob, user.getId());
        if (QuartzJobEnum.RESUME.getValue() == quartzJob.getStatus()) {
            // 任务状态为启动 更新定时任务
            QuartzUtils.update(quartzJob, scheduler);
        }
        //更新数据库
        updateById(quartzJob);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(User user, Long id) throws SchedulerException {
        QuartzJob quartzJob = selectById(id);
        //删除定时任务
        QuartzUtils.delete(quartzJob, scheduler);
        MyBeanUtils.updateSysInfo(quartzJob, user.getId());
        //删除数据库
        removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pause(Long id) throws SchedulerException {
        QuartzJob quartzJob = selectById(id);
        quartzJob.setStatus(QuartzJobEnum.PAUSE.getValue());
        //暂停任务
//        QuartzUtils.pause(quartzJob, scheduler);
        QuartzUtils.delete(quartzJob, scheduler);
        //更新数据库
        updateById(quartzJob);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resume(Long id) throws SchedulerException {
        QuartzJob quartzJob = selectById(id);
        quartzJob.setStatus(QuartzJobEnum.RESUME.getValue());
        QuartzUtils.createJob(quartzJob, scheduler);
        //更新数据库
        updateById(quartzJob);
    }

    @Override
    public QuartzJob selectById(Long id) {
        QuartzJob quartzJob = baseMapper.selectById(id);
        return quartzJob;
    }
}
